package com.thug.entities;

import java.util.Stack;

import org.anddev.andengine.entity.IEntity;
import org.anddev.andengine.entity.modifier.PathModifier;
import org.anddev.andengine.entity.modifier.PathModifier.IPathModifierListener;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.AnimatedSprite;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.thug.engine.BaseGameEntity;
import com.thug.engine.Utility;

public class Bot extends BaseGameEntity {

	public enum BotStates {
		BS_PATROL, BS_WANDER, BS_SEARCH, BS_SEEK
	}

	AnimatedSprite mSprite;
	Body mBody;

	Path mPatrolPathFwd;
	Path mPatrolPathRev;
	float mPatrolDuration;

	Path mCurrentPath;
	float mCurrentPathDuration;

	PathModifier mPathModifier;
	private Stack<BotStates> mBotStates;

	//
	private boolean mPathFinished;

	/*
	 * Animation stub
	 */
	private long[] mFrameDuration = new long[] { 100, 100, 100, 100 };
	private int[] mFrames = new int[] { 0, 1, 2, 3 };

	public Bot(AnimatedSprite s, Body b) {
		mEntityType = EntityType.ET_BOT;
		mSprite = s;
		mBody = b;
		mCurrentPath = null;
		mPathModifier = null;
		mBotStates = new Stack<Bot.BotStates>();
		mPathFinished = true;
	}

	@Override
	public void init() {
		// TODO Auto-generated method stub

	}

	@Override
	public void attach(Scene scene) {
		scene.attachChild(mSprite);
		// scene.attachChild(mVelLine);
	}

	@Override
	public void detach(Scene scene) {
		scene.detachChild(mSprite);

	}

	@Override
	public void update(float elapsedTime) {
	}

	@Override
	public void beginContact(Body bodyA, Body bodyB, Vector2 normal,
			Vector2[] points) {
		// TODO Auto-generated method stub

	}

	@Override
	public void endContact(Body bodyA, Body bodyB, Vector2 normal,
			Vector2[] points) {
		// TODO Auto-generated method stub

	}

	@Override
	public void dispose() {
		mSprite.detachSelf();
		mBody.getWorld().destroyBody(mBody);
		mSprite = null;
		mBody = null;

	}

	@Override
	public float getX() {
		//return mSprite.getX();
		float x = mSprite.getX() + mSprite.getBaseWidth() * 0.5f;
		return x;
	}

	@Override
	public float getY() {
		//return mSprite.getY();
		float y = mSprite.getY() + mSprite.getBaseHeight() * 0.5f;
		return y;
	}

	@Override
	public float getRotation() {
		return mSprite.getRotation();
	}
	
	public AnimatedSprite getSprite() { return mSprite; }

	public void startFollowing(Path path, float duration) {
		mCurrentPath = path;
		mCurrentPathDuration = duration;
		if (mPathModifier != null) {
			mSprite.unregisterEntityModifier(mPathModifier);
		}
		mPathModifier = new PathModifier(duration, path,
				new IPathModifierListener() {

					@Override
					public void onPathWaypointStarted(
							PathModifier pPathModifier, IEntity pEntity,
							int pWaypointIndex) {
						setAnimationFrames(pPathModifier.getPath(),
								pWaypointIndex);
					}

					@Override
					public void onPathWaypointFinished(
							PathModifier pPathModifier, IEntity pEntity,
							int pWaypointIndex) {
					}

					@Override
					public void onPathStarted(PathModifier pPathModifier,
							IEntity pEntity) {
						mPathFinished = false;
						setAnimationFrames(pPathModifier.getPath(), 0);

					}

					@Override
					public void onPathFinished(PathModifier pPathModifier,
							IEntity pEntity) {
						mPathFinished = true;
						mSprite.stopAnimation();
					}
				});

		mSprite.registerEntityModifier(mPathModifier);
	}

	
	public Path getPath() {
		return mCurrentPath;
	}

	public void setPath(Path path, float duration) {
		mCurrentPath = path;
		mCurrentPathDuration = duration;
	}

	public void startFollowing() {
		startFollowing(mCurrentPath, mCurrentPathDuration);
	}

	public BotStates getCurrentState() {
		return mBotStates.peek();
	}

	public void pushState(BotStates states) {
		mBotStates.push(states);
	}

	public BotStates popState() {
		return mBotStates.pop();
	}

	public boolean isStateStackEmpty() {
		return mBotStates.isEmpty();
	}

	public boolean isPathFinished() {
		return mPathFinished;
	}

	public void setPatrolPath(Path path, float duration) {
		mPatrolPathFwd = path;
		mPatrolPathRev = Utility.reversePath(path);
		mPatrolDuration = duration;
	}

	public void startPatroling() {
		if (mCurrentPath == mPatrolPathFwd) {
			mCurrentPath = mPatrolPathRev;
		} else if (mCurrentPath == mPatrolPathRev) {
			mCurrentPath = mPatrolPathFwd;
		} else {
			mCurrentPath = mPatrolPathFwd;
		}
		mCurrentPathDuration = mPatrolDuration;

		startFollowing();
	}

	private void setAnimationFrames(Path path, int index) {

		if (index < path.getSize() - 1) {
			float xPos = path.getCoordinatesX()[index + 1];
			float yPos = path.getCoordinatesY()[index + 1];
			float x = path.getCoordinatesX()[index];
			float y = path.getCoordinatesY()[index];

			x = xPos - x;
			y = yPos - y;

			float ang = (float) Math.atan2(y, x);
			ang = (float) Math.toDegrees(ang);
			if (ang < 0) {
				ang = ang + 360;
			}

			if (ang >= 315 || ang < 45) {
				setFrames(8); // right
			}

			else if (ang >= 45 && ang < 135) {
				setFrames(0); // down
			}

			else if (ang >= 135 && ang < 225) {
				setFrames(4); // left
			}

			else if (ang >= 225 && ang < 315) {
				setFrames(12); // up
			}

			mSprite.animate(mFrameDuration, mFrames, Integer.MAX_VALUE);
		}
	}

	// quad
	private void setFrames(int first) {
		mFrames[0] = first;
		mFrames[1] = first + 1;
		mFrames[2] = first + 2;
		mFrames[3] = first + 3;
	}
}